// CH6_2.cpp
// by Charles Mc Auley
// "Programming AutoCAD 2000 with ObjectARX"
//
//	This application is a redo of the Window application
//	of Chapter 5. The user interface now supports a DCL
//	style dialog.
//
/////////////////////////////////////////////////////////


#include <acdb.h>		// acdb definitions
#include <adslib.h>		// ads defs
#include <rxregsvc.h>	// unlock application
#include <aced.h>
#include <dbsymtb.h>	// Symbol Tables
#include <adsdlg.h>		// DCL style dialogs
#include <geassign.h>	// asDblArray
#include <dbapserv.h>	// acdbHostApplicationServices()

// TODO: add your own includes
#include "RectWindow.h"	// RectWindow class
#include "ArchWindow.h"	// ArchWindow class
#include "ApexWindow.h"	// ApexWindow Class


// Function prototypes
// entry point for this application
extern "C" AcRx::AppRetCode acrxEntryPoint( AcRx::AppMsgCode msg, void* );

// helper functions
void initApp  (void);
void unloadApp(void);

// user defined functions
void windo();
Adesk::Boolean getModelSpaceRecord(AcDbBlockTableRecord*& pBlkTableRecord);


// Dialog call back function prototypes
static void CALLB dlgOkBtnCB(ads_callback_packet *cpkt);

// Global variables, place holders for the values
// obtained from the dialog box

double	g_winHt, g_winWidth;
int		g_Rows, g_Cols;
char	g_strWinType[10];
Adesk::Boolean g_bProceed = Adesk::kFalse;
Adesk::Boolean g_bWindoParamSet = Adesk::kFalse;


/////////////////////////////////////////////////////////////////////
// acrxEntryPoint(internal)
// This function is the entry point for your application.
/////////////////////////////////////////////////////////////////////
AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* ptr)
{
	switch (msg) {
		case AcRx::kInitAppMsg :
			acrxUnlockApplication(ptr);
			acrxRegisterAppNotMDIAware(ptr);
			initApp();
		break;

		case AcRx::kUnloadAppMsg :
			unloadApp();
		break;

		case AcRx::kLoadDwgMsg :
		break;

		case AcRx::kUnloadDwgMsg :
		break;

		default:
		break;
	} // switch

  return AcRx::kRetOK;
}

void initApp(void)
{
	// TODO: init your application
    // register a command with the AutoCAD command mechanism

    acedRegCmds->addCommand("CH6_APPS", "WINDO", "WINDO",
                    ACRX_CMD_MODAL, windo);
	acutPrintf("Enter \"WINDO\" at the command prompt to draw a window.\n");

}

void unloadApp(void)
{
	// TODO: clean up your application
    // Remove the command group added via acedRegCmds->addCommand

	acutPrintf("%s%s", "Goodbye\n", "Removing command group \"CH6_APPS\"\n");
    acedRegCmds->removeGroup("CH6_APPS");

}

// TODO: add your other functions here

void windo()
{

	int rc; // Return code
	char dclFile[TILE_STR_LIMIT];	// TILE_STR_LIMIT = 255 in adsdlg.h file
	char dclName[80];
	int dclId, dbStat;				// dcl ID and dialog box status
	ads_hdlg dlgHdl;				// Dialog Box handle

	AcDbBlockTableRecord *pBlkTableRecord;

	RectWindow *pRectWindow;	// RectWindow class
	ArchWindow *pArchWindow;	// Derived ArchWindow class
	ApexWindow *pApexWindow;	// Derived ApexWindow class
	RectWindow *pGenericWind;

	AcGePoint2d startPt;
	AcGePoint3d pickPt;			// Lower left point of the window

	char buffer[80];	// Used in the conversion of numbers to string


	strcpy(dclFile, "ch6_2.dcl");
	strcpy(dclName, "ch6_2");
	
	rc = ads_load_dialog(dclFile, &dclId);
	if(rc != RTNORM)
	{
		acutPrintf("%s %s", "\nError loading Ch6_2.DCL file. ", dclFile);
		return;
	}

	// Now that the dialog is loaded, display it
	rc = ads_new_dialog(dclName, dclId, NULLCB, &dlgHdl);
	if(rc != RTNORM)
	{
		acutPrintf("\nError displaying dialog. ");
		return;
	}

	// Now that the dialog is visible on the screen
	// initialize it.
	if(g_bWindoParamSet)
	{
		if(strcmp(g_strWinType, "rb_rect") == 0)
		{
			ads_set_tile(dlgHdl, "rb_rect", "1");
		}
		else if(strcmp(g_strWinType, "rb_arch") == 0)
		{
			ads_set_tile(dlgHdl, "rb_arch", "1");
		}
		else if(strcmp(g_strWinType, "rb_apex") == 0)
		{
			ads_set_tile(dlgHdl, "rb_apex", "1");
		}
		else
		{
			ads_set_tile(dlgHdl, "eb_height", "20.00");
			ads_set_tile(dlgHdl, "eb_width", "20.00");
		}

		// Convert the doubles for the height and width
		_gcvt(g_winHt, 10, buffer);
		ads_set_tile(dlgHdl, "eb_height", buffer);
		_gcvt(g_winWidth, 10, buffer);
		ads_set_tile(dlgHdl, "eb_width", buffer);

		// Convert the integers for the rows and columns
		_itoa(g_Cols, buffer, 10);
		ads_set_tile(dlgHdl, "eb_cols", buffer);
		_itoa(g_Rows, buffer, 10);
		ads_set_tile(dlgHdl, "eb_rows", buffer);

	}
	else
	{
		ads_set_tile(dlgHdl, "eb_height", "20.00");
		ads_set_tile(dlgHdl, "eb_width", "20.00");
	}

	ads_action_tile(dlgHdl, "accept", dlgOkBtnCB);

	rc = ads_start_dialog(dlgHdl, &dbStat);
	if(rc != RTNORM)
	{
		acutPrintf("\nFailed to initialize the dialog box. ");
		return;
	}
	
	// Unload the dialog box
	ads_unload_dialog(dclId);

	if(g_bProceed)
	{

		acedInitGet(NULL, NULL);
		rc = acedGetPoint(NULL, "\nPick lower left window insertion point <Return for (0,0)>: ", 
					asDblArray(pickPt));

		switch(rc)
		{
			case RTCAN:
			case RTERROR:
				return;

			case RTNONE:
				startPt.x = 0;
				startPt.y = 0;
			break;

			case RTNORM:
				startPt.x = pickPt.x;
				startPt.y = pickPt.y;
			break;
		}

		// What kind of window did the user select?
		if(strcmp(g_strWinType, "rb_rect") == 0)
		{
			pRectWindow = new RectWindow;
			pGenericWind = pRectWindow;
		}
		else if(strcmp(g_strWinType, "rb_arch") == 0)
		{
			pArchWindow = new ArchWindow;
			pGenericWind = pArchWindow;
		}
		else if(strcmp(g_strWinType, "rb_apex") == 0)
		{
			pApexWindow = new ApexWindow;
			pGenericWind = pApexWindow;
		}
		else
		{
			return;
		}

		// Fill out the window class object
		// with the input values

		pGenericWind->setWindowLength(g_winWidth);
		pGenericWind->setWindowHeight(g_winHt);
		pGenericWind->setWindowCols(g_Cols);
		pGenericWind->setWindowRows(g_Rows);
		pGenericWind->setWindowStartPoint(startPt);

		if(!getModelSpaceRecord(pBlkTableRecord))
		{
			return;
		}

		pGenericWind->drawWindow(pBlkTableRecord);

		if(pGenericWind != NULL)
		{
			delete pGenericWind;
		}

		pBlkTableRecord->close();
		
		// Set the boolean back to false, because
		// in the next invocation of the application
		// AutoCAD remembers the values of the global
		// variables.
		g_bProceed = Adesk::kFalse;
		g_bWindoParamSet = Adesk::kTrue;

	}// if g_bProceed
	else
	{
		acutPrintf("\nUser cancelled. ");
	}

}

// Dialog Box callback functions

static void CALLB dlgOkBtnCB(ads_callback_packet *cpkt)
{
	char strWinHt[100];
	char strWinWidth[100];
	char strWinRows[20];
	char strWinCols[20];
	char strWinType[10];

	int rc;
	double winHt, winWidth;
	int winRows, winCols;

	
	// Get the window height
	rc = ads_get_tile(cpkt->dialog, "eb_height", strWinHt, 80);
	if(rc != RTNORM)
	{
		ads_done_dialog(cpkt->dialog, DLGOK);
		acutPrintf("\nError in Height edit box. ");
		return;
	}
	winHt = atof(strWinHt);
	if(winHt <= 0.0)
	{
		ads_done_dialog(cpkt->dialog, DLGOK);
		acutPrintf("\nInvalid value for window Height. ");
		return;
	}

	// Get the window width
	rc = ads_get_tile(cpkt->dialog, "eb_width", strWinWidth, 80);
	if(rc != RTNORM)
	{
		ads_done_dialog(cpkt->dialog, DLGOK);
		acutPrintf("\nError in Width edit box. ");
		return;
	}
	winWidth = atof(strWinWidth);
	if(winWidth <= 0.0)
	{
		ads_done_dialog(cpkt->dialog, DLGOK);
		acutPrintf("\nInvalid value for window width. ");
		return;
	}

	// Get the number of window columns
	rc = ads_get_tile(cpkt->dialog, "eb_cols", strWinCols, 20);
	if(rc != RTNORM)
	{
		ads_done_dialog(cpkt->dialog, DLGOK);
		acutPrintf("\nError in Columns edit box. ");
		return;
	}
	winCols = atoi(strWinCols);
	if(winCols < 1)
	{
		acedAlert("Invalid value for window columns.\nMinimum value = 1");
		ads_mode_tile(cpkt->dialog, "eb_cols", MODE_SETFOCUS);
	}

	// Get the number of window rows
	rc = ads_get_tile(cpkt->dialog, "eb_rows", strWinRows, 20);
	if(rc != RTNORM)
	{
		ads_done_dialog(cpkt->dialog, DLGOK);
		acutPrintf("\nError in Rows edit box. ");
		return;
	}
	winRows = atoi(strWinRows);
	if(winRows < 1)
	{
		acedAlert("Invalid value for window rows.\nMinimum value = 1");
		ads_mode_tile(cpkt->dialog, "eb_rows", MODE_SETFOCUS);
	}

	// The following ads_get_tile() call will place in strWinType
	// the key of the radio button that is selected in other words
	// the radio button that has a value of "1". The key brc_wintype
	// is a boxed_radio_column tile that contains radio_button tiles.

	rc = ads_get_tile(cpkt->dialog, "brc_wintype", strWinType, 10);
	if(rc != RTNORM)
	{
		ads_done_dialog(cpkt->dialog, DLGOK);
		acutPrintf("\nError in window type. ");
		return;
	}


	ads_done_dialog(cpkt->dialog, DLGOK);

	// Transfer the values obtained to the global
	// variables.

	g_winHt		= winHt;
	g_winWidth	= winWidth;
	g_Cols		= winCols;
	g_Rows		= winRows;

	strcpy(g_strWinType, strWinType);

	g_bProceed = Adesk::kTrue;
}


// User defined functions

Adesk::Boolean getModelSpaceRecord(AcDbBlockTableRecord*& pBlkTableRecord)
{
	AcDbDatabase *pCurDb;
	AcDbBlockTable *pBlkTable;
	Acad::ErrorStatus es;

	pCurDb = acdbHostApplicationServices()->workingDatabase();

	es = pCurDb->getBlockTable(pBlkTable, AcDb::kForRead);
	if(es != Acad::eOk)
	{
		acutPrintf("\nFailed to open Block Table for a read operation.");
		return Adesk::kFalse;
	}

	es = pBlkTable->getAt(ACDB_MODEL_SPACE, pBlkTableRecord, AcDb::kForWrite);
	if(es != Acad::eOk)
	{
		acutPrintf("\nFailed to open MODEL SPACE for a write operation.");
		pBlkTable->close();
		return Adesk::kFalse;
	}

	// We don't need the block table anymore so we can close it.
	pBlkTable->close();

	return Adesk::kTrue;
}